﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AuthorizePolicy.JWT;
using Core.BLL.Service;
using Core.EF;
using Core.EF.Repositories;
using Core.InterFace.Interface;
using coreEntityFramework.Extend;
using coreEntityFramework.Extend.attrible;
using coreEntityFramework.Extend.Permission;
using Hangfire;
using Hangfire.Storage;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using NLog;
using NLog.Extensions.Logging;

namespace coreEntityFramework
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
               .SetBasePath(env.ContentRootPath)
               .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
               .AddJsonFile("config.json", optional: true, reloadOnChange: true);

            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {


            var urls = "http://localhost:7292/";



            //跨域
            services.AddCors(options =>
            options.AddPolicy("MyDomain",
            builder => builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials())); //添加跨域设置

            services.AddTransient<IMessageService, MessageService>();
            services.AddTransient<IAccountService, AccountService>();

            #region hanfire服务
            //增加hangfire服务
            services.AddHangfire(x => x.UseSqlServerStorage("Data Source=.;Initial Catalog=BloggingDB1;Integrated Security=True"));
            #endregion


            #region 精简版的jwt

            //var audienceConfig = Configuration.GetSection("Audience");
            //var symmetricKeyAsBase64 = audienceConfig["Secret"];

            //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            //   .AddJwtBearer(options =>
            //   {
            //       options.TokenValidationParameters = new TokenValidationParameters
            //       {
            //           ValidateIssuer = true,
            //           ValidateAudience = true,
            //           ValidateLifetime = true,
            //           ValidateIssuerSigningKey = true,
            //           ValidIssuer = "lilibuy.com",
            //           ValidAudience = "lilibuy.com",
            //           ClockSkew = TimeSpan.FromSeconds(30),
            //           IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(symmetricKeyAsBase64))//Configuration["JWT:SecurityKey"]
            //       };
            //   });

            #endregion



            #region  JWT 权限
            //读取配置  JWT 权限
            var audienceConfig = Configuration.GetSection("Audience");
            var symmetricKeyAsBase64 = audienceConfig["Secret"];
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = audienceConfig["Issuer"],//发行人
                ValidateAudience = true,
                ValidAudience = audienceConfig["Audience"],//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
                RequireExpirationTime = true,

            };

            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            //这个集合模拟用户权限表,可从数据库中查询出来
            var permission = new List<Permission> {
                              new Permission {  Url="/", Name="admin"},
                              new Permission {  Url="/api/values", Name="admin"},
                              new Permission {  Url="/", Name="system"},
                              new Permission {  Url="/api/val1", Name="system"}
                          };


            //如果第三个参数，是ClaimTypes.Role，上面集合的每个元素的Name为角色名称，如果ClaimTypes.Name，即上面集合的每个元素的Name为用户名
            var permissionRequirement = new PermissionRequirement(
                "/api/denied", permission,
                ClaimTypes.Role,
                audienceConfig["Issuer"],
                audienceConfig["Audience"],
                signingCredentials,
                expiration: TimeSpan.FromSeconds(10)
                );

            services.AddAuthorization(options =>
            {

                options.AddPolicy("Permission",
                          policy => policy.Requirements.Add(permissionRequirement));

            }).AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                //不使用https
                o.RequireHttpsMetadata = false;
                o.TokenValidationParameters = tokenValidationParameters;
                o.Events = new JwtBearerEvents
                {
                    OnTokenValidated = context =>
                    {
                        if (context.Request.Path.Value.ToString() == "/api/logout")
                        {
                            var token = ((context as TokenValidatedContext).SecurityToken as JwtSecurityToken).RawData;
                        }
                        return Task.CompletedTask;
                    }
                };
            });

            ////注入授权Handler
            //services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
            //services.AddSingleton(permissionRequirement);
            #endregion

            #region 数据库
            var sqlConnectionString = Configuration.GetConnectionString("DataAccessMsSqlServerProvider");

            #region 注入
            services.AddTransient(typeof(IEntityBaseRepository<>), typeof(EntityBaseRepository<>));
            services.AddTransient(typeof(ITestService), typeof(TestService));
            #endregion

            #endregion

            services.AddDbContext<MyContext>(options =>
                options.UseSqlServer(
                    sqlConnectionString,
                    b => b.MigrationsAssembly("coreEntityFramework")
                )
            );

            services.AddMvc(cfg =>
            {
                cfg.Filters.Add(typeof(AuditLogFilter)); //添加全局filter,可以写审计日志   扩展点1
                cfg.Filters.Add(typeof(ValidParameterAttribute)); //全局验证 参数
                //cfg.Filters.Add(typeof(StringLengthAttribute));
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseCors("AllowSameDomain");


            #region hanfire配置

            var jobOptions = new BackgroundJobServerOptions
            {
                Queues = new[] { "test", "default" },//队列名称，只能为小写
                WorkerCount = Environment.ProcessorCount * 5, //并发任务数
                ServerName = "hangfire1",//服务器名称
            };
            app.UseHangfireServer(jobOptions);
            app.UseHangfireDashboard();


            RecurringJob.AddOrUpdate<IMessageService>((servic) => servic.SendMessage("ssss")
            , Cron.Minutely);
            RecurringJob.AddOrUpdate<IMessageService>((servic) => servic.GetMessage("ssss")
                        , Cron.Minutely);
            //RecurringJob.AddOrUpdate(() => SchedulePollingBackgroundJob(), @"*/5 * * * * ", TimeZoneInfo.Local);


            #endregion

            app.UseAuthentication(); //登陆认证

            app.Use(async (content, next) =>
            {

                await next.Invoke();
            });
            //添加权限中间件, 一定要放在app.UseAuthentication后
            app.UsePermission(new PermissionMiddlewareOption()  //权限
            {
                LoginAction = @"/login",
                NoPermissionAction = @"/denied",
                //这个集合从数据库中查出所有用户的全部权限
                UserPerssions = new List<UserPermission>()
                           {
                             new UserPermission { Url = "/", UserName = "gsw" },
                             new UserPermission { Url = "/home/contact", UserName = "gsw" },
                             new UserPermission { Url = "/api/Test", UserName = "aaa" },
                             new UserPermission { Url = "/", UserName = "aaa" }
                           }
            });

            //新增日志模块 替换微软的日志  扩展点2
            loggerfactory.AddNLog();
            NLog.LogManager.LoadConfiguration($@"{env.ContentRootPath}/nlog.config");//指定NLog的配置文件

            //全局异常处理   扩展点3
            app.UseExcetionOption();

            app.UseMvc();
        }


    }
}
